package msi.gama.display.java3d;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Frame;
import java.awt.Point;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;

import msi.gama.common.interfaces.IDisplaySurface;
import msi.gama.common.interfaces.ILayerManager;
import msi.gama.display.java3d.renderer.J3DRenderer;
import msi.gama.gui.displays.awt.AbstractAWTDisplaySurface;
import msi.gama.gui.swt.SwtGui;
import msi.gama.gui.views.Java3DDisplayView;
import msi.gama.metamodel.agent.IAgent;
import msi.gama.metamodel.shape.GamaPoint;
import msi.gama.metamodel.shape.ILocation;
import msi.gama.metamodel.shape.IShape;
import msi.gama.outputs.LayeredDisplayOutput;
import msi.gama.outputs.display.LayerManager;
import msi.gama.precompiler.GamlAnnotations.display;
import msi.gama.runtime.IScope;
import msi.gama.util.IList;

import org.eclipse.swt.awt.SWT_AWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.IViewReference;

/**
 * minhvv, p18, IFI, TPE 01/2014 - 07/2014
 */

@display("java3d")
public class J3DDisplaySurface extends AbstractAWTDisplaySurface implements IDisplaySurface {
	private static final long serialVersionUID = -1987860348416215562L;

	private String fullViewName = "";
	private Frame drawingFrame = null;

	public J3DDisplaySurface(final Object... args) {
		createIGraphics();

		this.displayBlock = new Runnable() {

			@Override
			public void run() {
				System.err.println("J3DDisplaySurface entering displayBlock");

				if (!J3DRenderer.isSceneGraphReady()) {
					return;
				}

				J3DRenderer.beginRenderingOneFrame();
				{
					canBeUpdated(false);
					drawDisplayAndUpdateSceneGraph();
					canBeUpdated(true);
				}
				J3DRenderer.endRenderingOneFrame();

				System.err.println("J3DDisplaySurface leaving displayBlock");
			}
		};
	}

	public void drawDisplayAndUpdateSceneGraph() {
		if (iGraphics == null) {
			System.err.println("Graphics null");
			return;
		}

		if (null == manager) {
			System.err.println("Manager null");
			return;
		}

		manager.drawLayersOn(iGraphics);
	}

	/**
	 * Method getImage()
	 * 
	 * @see msi.gama.common.interfaces.IDisplaySurface#getImage()
	 */
	@Override
	public BufferedImage getImage() {
		return null;
	}

	/**
	 * Method dispose()
	 * 
	 * @see msi.gama.common.interfaces.IDisplaySurface#dispose()
	 */
	@Override
	public void dispose() {
		if (null != manager) {
			manager.dispose();
		}
	}

	/**
	 * Method updateDisplay()
	 * 
	 * @see msi.gama.common.interfaces.IDisplaySurface#updateDisplay()
	 */
	@Override
	public void updateDisplay() {
		super.updateDisplay();

		if (!J3DRenderer.isRenderingSurfaceCreated()) {
			initRenderingSurface();
		}

	}

	private void initRenderingSurface() {
		if (null == drawingFrame) {
			createDrawingFrame();
		}

		if (null != drawingFrame) {
			attackRenderingSurfaceToFrame();
		}
	}

	private void createDrawingFrame() {
		SwtGui.getDisplay().syncExec(new Runnable() {

			@Override
			public void run() {
				try {
					IViewReference[] listViews = SwtGui.getPage().getViewReferences();

					for (IViewReference viewRef : listViews) {
						if (viewRef.getId().equals(fullViewName)) {
							Java3DDisplayView java3dDisplayView =
									(Java3DDisplayView) viewRef.getView(true);
							Composite displayComponent = java3dDisplayView.getComponent();
							drawingFrame = SWT_AWT.new_Frame(displayComponent);
							drawingFrame.setLayout(new BorderLayout());
						}
					}
				} catch (final Exception e) {
					e.printStackTrace();
				}

			}
		});
	}

	private void attackRenderingSurfaceToFrame() {
		drawingFrame.add(J3DRenderer.createRenderingSurface(), BorderLayout.CENTER);
		J3DRenderer.createSceneGraphEnvironment();
	}

	// private BranchGroup createSceneGraph() {
	// BranchGroup objRoot = new BranchGroup();
	//
	// objRoot.addChild(new ColorCube(0.3));
	//
	// return objRoot;
	// }

	/**
	 * Method forceUpdateDisplay()
	 * 
	 * @see msi.gama.common.interfaces.IDisplaySurface#forceUpdateDisplay()
	 */
	@Override
	public void forceUpdateDisplay() {
	}

	/**
	 * Method computeBoundsFrom()
	 * 
	 * @see msi.gama.common.interfaces.IDisplaySurface#computeBoundsFrom(int,int)
	 */
	@Override
	public int[] computeBoundsFrom(final int width, final int height) {
		return null;
	}

	/**
	 * Method resizeImage()
	 * 
	 * @see msi.gama.common.interfaces.IDisplaySurface#resizeImage(int, int)
	 */
	@Override
	public boolean resizeImage(final int width, final int height) {
		// super.resizeImage(width, height);
		// setSize(width, height);
		return true;
	}

	/**
	 * Method zoomIn()
	 * 
	 * @see msi.gama.common.interfaces.IDisplaySurface#zoomIn()
	 */
	@Override
	public void zoomIn() {
	}

	/**
	 * Method zoomOut()
	 * 
	 * @see msi.gama.common.interfaces.IDisplaySurface#zoomOut()
	 */
	@Override
	public void zoomOut() {
	}

	/**
	 * Method zoomFit()
	 * 
	 * @see msi.gama.common.interfaces.IDisplaySurface#zoomFit()
	 */
	@Override
	public void zoomFit() {
	}

	/**
	 * Method getManager()
	 * 
	 * @see msi.gama.common.interfaces.IDisplaySurface#getManager()
	 */
	@Override
	public ILayerManager getManager() {
		return new LayerManager(this);
	}

	/**
	 * Method focusOn()
	 * 
	 * @see msi.gama.common.interfaces.IDisplaySurface#focusOn(msi.gama.metamodel.shape.IShape,
	 *      msi.gama.common.interfaces.ILayer)
	 */
	@Override
	public void focusOn(final IShape geometry) {
	}

	// /**
	// * Method canBeUpdated()
	// *
	// * @see msi.gama.common.interfaces.IDisplaySurface#canBeUpdated()
	// */
	// @Override
	// public boolean canBeUpdated() {
	// return false;
	// }

	// /**
	// * Method canBeUpdated()
	// *
	// * @see msi.gama.common.interfaces.IDisplaySurface#canBeUpdated(boolean)
	// */
	// @Override
	// public void canBeUpdated(final boolean ok) {
	// }

	/**
	 * Method setBackgroundColor()
	 * 
	 * @see msi.gama.common.interfaces.IDisplaySurface#setBackgroundColor(java.awt.Color)
	 */
	@Override
	public void setBackgroundColor(final Color background) {
	}

	/**
	 * Method setPaused()
	 * 
	 * @see msi.gama.common.interfaces.IDisplaySurface#setPaused(boolean)
	 */
	@Override
	public void setPaused(final boolean b) {
	}

	/**
	 * Method isPaused()
	 * 
	 * @see msi.gama.common.interfaces.IDisplaySurface#isPaused()
	 */
	@Override
	public boolean isPaused() {
		return false;
	}

	/**
	 * Method setQualityRendering()
	 * 
	 * @see msi.gama.common.interfaces.IDisplaySurface#setQualityRendering(boolean)
	 */
	@Override
	public void setQualityRendering(final boolean quality) {
	}

	/**
	 * Method setSynchronized()
	 * 
	 * @see msi.gama.common.interfaces.IDisplaySurface#setSynchronized(boolean)
	 */
	@Override
	public void setSynchronized(final boolean checked) {
	}

	/**
	 * Method setAutoSave()
	 * 
	 * @see msi.gama.common.interfaces.IDisplaySurface#setAutoSave(boolean, int,
	 *      int)
	 */
	@Override
	public void setAutoSave(final boolean autosave, final int x, final int y) {
	}

	/**
	 * Method initOutput3D()
	 * 
	 * @see msi.gama.common.interfaces.IDisplaySurface#initOutput3D(boolean,
	 *      msi.gama.metamodel.shape.ILocation)
	 */
	@Override
	public void initOutput3D(final boolean output3d, final ILocation output3dNbCycles) {
	}

	/**
	 * Method setSnapshotFileName()
	 * 
	 * @see msi.gama.common.interfaces.IDisplaySurface#setSnapshotFileName(java.lang.String)
	 */
	@Override
	public void setSnapshotFileName(final String string) {
	}

	/**
	 * Method snapshot()
	 * 
	 * @see msi.gama.common.interfaces.IDisplaySurface#snapshot()
	 */
	@Override
	public void snapshot() {
	}

	/**
	 * Method getWidth()
	 * 
	 * @see msi.gama.common.interfaces.IDisplaySurface#getWidth()
	 */
	@Override
	public int getWidth() {
		return 0;
	}

	/**
	 * Method getHeight()
	 * 
	 * @see msi.gama.common.interfaces.IDisplaySurface#getHeight()
	 */
	@Override
	public int getHeight() {
		return 0;
	}

	/**
	 * Method getImageWidth()
	 * 
	 * @see msi.gama.common.interfaces.IDisplaySurface#getImageWidth()
	 */
	@Override
	public int getImageWidth() {
		return 0;
	}

	/**
	 * Method getImageHeight()
	 * 
	 * @see msi.gama.common.interfaces.IDisplaySurface#getImageHeight()
	 */
	@Override
	public int getImageHeight() {
		return 0;
	}

	/**
	 * Method setOrigin()
	 * 
	 * @see msi.gama.common.interfaces.IDisplaySurface#setOrigin(int, int)
	 */
	@Override
	public void setOrigin(final int i, final int j) {
	}

	/**
	 * Method getOriginX()
	 * 
	 * @see msi.gama.common.interfaces.IDisplaySurface#getOriginX()
	 */
	@Override
	public int getOriginX() {
		return 0;
	}

	/**
	 * Method getOriginY()
	 * 
	 * @see msi.gama.common.interfaces.IDisplaySurface#getOriginY()
	 */
	@Override
	public int getOriginY() {
		return 0;
	}

	/**
	 * Method initialize()
	 * 
	 * @see msi.gama.common.interfaces.IDisplaySurface#initialize(double,
	 *      double, msi.gama.outputs.LayeredDisplayOutput)
	 */
	@Override
	public void initialize(final IScope scope, final double w, final double h,
			final LayeredDisplayOutput output) {

		super.initialize(scope, w, h, output);

		String viewId = output.getViewId();
		String viewName = output.getViewName();
		this.fullViewName = viewId + ":" + viewName;

	}

	/**
	 * Method outputChanged()
	 * 
	 * @see msi.gama.common.interfaces.IDisplaySurface#outputChanged(double,
	 *      double, msi.gama.outputs.LayeredDisplayOutput)
	 */
	@Override
	public void outputChanged(final IScope scope, final double env_width,
			final double env_height,
			final LayeredDisplayOutput output) {
		super.outputChanged(scope, env_width, env_height, output);
	}

	/**
	 * Method getHighlightColor()
	 * 
	 * @see msi.gama.common.interfaces.IDisplaySurface#getHighlightColor()
	 */
	@Override
	public int[] getHighlightColor() {
		return null;
	}

	/**
	 * Method setHighlightColor()
	 * 
	 * @see msi.gama.common.interfaces.IDisplaySurface#setHighlightColor(int[])
	 */
	@Override
	public void setHighlightColor(final int[] rgb) {
	}

	/**
	 * Method addMouseListener()
	 * 
	 * @see msi.gama.common.interfaces.IDisplaySurface#addMouseListener(java.awt.event.MouseListener)
	 */
	@Override
	public void addMouseListener(final MouseListener e) {
	}

	/**
	 * Method getEnvWidth()
	 * 
	 * @see msi.gama.common.interfaces.IDisplaySurface#getEnvWidth()
	 */
	@Override
	public double getEnvWidth() {
		return 0;
	}

	/**
	 * Method getEnvHeight()
	 * 
	 * @see msi.gama.common.interfaces.IDisplaySurface#getEnvHeight()
	 */
	@Override
	public double getEnvHeight() {
		return 0;
	}

	/**
	 * Method getDisplayWidth()
	 * 
	 * @see msi.gama.common.interfaces.IDisplaySurface#getDisplayWidth()
	 */
	@Override
	public int getDisplayWidth() {
		return 0;
	}

	/**
	 * Method getDisplayHeight()
	 * 
	 * @see msi.gama.common.interfaces.IDisplaySurface#getDisplayHeight()
	 */
	@Override
	public int getDisplayHeight() {
		return 0;
	}

	/**
	 * Method setZoomListener()
	 * 
	 * @see msi.gama.common.interfaces.IDisplaySurface#setZoomListener(msi.gama.common.interfaces.IDisplaySurface.IZoomListener)
	 */
	@Override
	public void setZoomListener(final IZoomListener listener) {
	}

	/**
	 * Method getModelCoordinates()
	 * 
	 * @see msi.gama.common.interfaces.IDisplaySurface#getModelCoordinates()
	 */
	@Override
	public GamaPoint getModelCoordinates() {
		return null;
	}

	/**
	 * Method isSynchronized()
	 * 
	 * @see msi.gama.common.interfaces.IDisplaySurface#isSynchronized()
	 */
	@Override
	public boolean isSynchronized() {
		return false;
	}

	/**
	 * Method followAgent()
	 * 
	 * @see msi.gama.common.interfaces.IDisplaySurface#followAgent(msi.gama.metamodel.agent.IAgent)
	 */
	@Override
	public void followAgent(final IAgent a) {
	}

	/**
	 * Method getZoomLevel()
	 * 
	 * @see msi.gama.common.interfaces.IDisplaySurface#getZoomLevel()
	 */
	@Override
	public double getZoomLevel() {
		return 0;
	}

	/**
	 * Method setSize()
	 * 
	 * @see msi.gama.common.interfaces.IDisplaySurface#setSize(int, int)
	 */
	@Override
	public void setSize(final int x, final int y) {
		// super.setSize(x, y);
	}

	/**
	 * Method getQualityRendering()
	 * 
	 * @see msi.gama.common.interfaces.IDisplaySurface#getQualityRendering()
	 */
	@Override
	public boolean getQualityRendering() {
		return false;
	}

	/**
	 * Method removeMouseListener()
	 * 
	 * @see msi.gama.common.interfaces.IDisplaySurface#removeMouseListener(java.awt.event.MouseListener)
	 */
	@Override
	public void removeMouseListener(final MouseListener e) {
	}

	@Override
	public GamaPoint getModelCoordinatesFrom(final int xOnScreen, final int yOnScreen,
			final Point sizeInPixels, final Point positionInPixels) {
		return null;
	}

	@Override
	public IList<IAgent> selectAgent(final int x, final int y) {
		return null;
	}

	@Override
	protected void createIGraphics() {
		if (null == this.iGraphics) {
			this.iGraphics = new J3DDisplayGraphics(this);
		}

	}

	@Override
	protected Double computeInitialZoomLevel() {
		return null;
	}

}
